package com.ltkj.pay.controller;


import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.ltkj.common.core.constant.HttpStatus;
import com.ltkj.common.core.domain.R;
import com.ltkj.common.core.utils.DateUtils;
import com.ltkj.common.core.web.controller.BaseController;
import com.ltkj.common.core.web.domain.AjaxResult;
import com.ltkj.common.security.utils.SecurityUtils;
import com.ltkj.pay.config.WechatPayConfig;
import com.ltkj.pay.config.WechatPayValidator;
import com.ltkj.pay.domain.TicPayLog;
import com.ltkj.pay.domain.TicPayRefundLog;
import com.ltkj.pay.service.ITicPayLogService;
import com.ltkj.pay.service.ITicPayRefundLogService;
import com.ltkj.system.api.RemoteOrderService;
import com.ltkj.system.api.RemoteTicketService;
import com.ltkj.system.api.domain.TicOrder;
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
/**
 * @Author gushaoliang
 * @Date 2023/9/12 14:50
 * @PackageName:com.ltkj.pay.controller
 * @ClassName: CallbackController
 * @Description: 支付退款回掉
 * @Version 1.0
 */
@Api(tags = "回调模块")
@RestController
@RequestMapping("/callback")
public class CallbackController extends BaseController {

    @Resource
    private WechatPayConfig wechatPayConfig;

    @Resource
    private Verifier verifier;
    @Autowired
    private RemoteTicketService remoteTicketService;
    @Autowired
    private RemoteOrderService remoteOrderService;
    private final ReentrantLock lock = new ReentrantLock();
    @Autowired
    private ITicPayLogService ticPayLogService;
    @Autowired
    private ITicPayRefundLogService ticPayRefundLogService;
    /**
     * 支付回调处理
     *
     * @param request
     * @param response
     * @return
     */
    @ApiOperation("支付回调处理")
    @PostMapping("/payNotify")
    public Map<String, String> payNotify(HttpServletRequest request, HttpServletResponse response) {
        logger.info("支付回调");


        // 处理通知参数
        Map<String, Object> bodyMap = getNotifyBody(request);
        logger.info("支付回调参数："+bodyMap);
        if (bodyMap == null) {
            return falseMsg(response);
        }

        logger.warn("=========== 在对业务数据进行状态检查和处理之前，要采用数据锁进行并发控制，以避免函数重入造成的数据混乱 ===========");
        if (lock.tryLock()) {
            try {
                // 解密resource中的通知数据
                String resource = bodyMap.get("resource").toString();
                logger.info("解密resource中的通知数据："+resource);
                Map<String, Object> resourceMap = WechatPayValidator.decryptFromResource(resource, wechatPayConfig.getApiV3Key(), 1);
                logger.info("解密之后中的通知数据："+resourceMap);
                String orderNo = resourceMap.get("out_trade_no").toString();
                // String transactionId = resourceMap.get("transaction_id").toString();
                // 更改状态 获取订单号  修改订单状态为已支付
                //查询订单信息
                R<TicOrder> ticOrderR = remoteOrderService.orderPayDetail(orderNo);
                if(ticOrderR.getCode()!= HttpStatus.SUCCESS){
                    logger.error("订单不存在");
                }else {
                    TicOrder data = ticOrderR.getData();
                    logger.info("订货信息，"+data.toString());
                    String orderStatus = data.getOrderStatus();
                    if(orderStatus.equals("1")){
                        AjaxResult ajaxResult = remoteTicketService.paySucessStatus(data.getOrderId());
                        logger.info("修改订单信息成功，"+ajaxResult.toString());

                        try {
                            TicPayLog ticPayLog = ticPayLogService.selectTicPayLogByWxOrderNum(orderNo);
                            if(ticPayLog!=null){
                                ticPayLog.setPayNotifyJson(JSONObject.toJSONString(resourceMap));
                                ticPayLog.setUpdateBy(SecurityUtils.getUsername());
                                ticPayLog.setUpdateTime(DateUtils.getNowDate());
                                ticPayLogService.updateTicPayLog(ticPayLog);
                            }
                        } catch (Exception e) {
                            logger.error(String.format("支付回调修改记录异常%s", e.getMessage()));
                        }


                    }

                }

                // TODO 根据订单号，做幂等处理，并且在对业务数据进行状态检查和处理之前，要采用数据锁进行并发控制，以避免函数重入造成的数据混乱
                logger.warn("=========== 根据订单号，做幂等处理 ===========");
            } finally {
                //要主动释放锁
                lock.unlock();
            }
        }

        //成功应答
        return trueMsg(response);
    }

    /**
     * 退款回调处理
     *
     * @param request
     * @param response
     * @return
     */
    @ApiOperation("退款回调处理")
    @PostMapping("/refundNotify")
    public Map<String, String> refundNotify(HttpServletRequest request, HttpServletResponse response) {
        logger.info("退款回调");

        // 处理通知参数
        Map<String, Object> bodyMap = getNotifyBody(request);
        if (bodyMap == null) {
            return falseMsg(response);
        }

        logger.warn("=========== 在对业务数据进行状态检查和处理之前，要采用数据锁进行并发控制，以避免函数重入造成的数据混乱 ===========");
        if (lock.tryLock()) {
            try {
                // 解密resource中的通知数据
                String resource = bodyMap.get("resource").toString();
                Map<String, Object> resourceMap = WechatPayValidator.decryptFromResource(resource, wechatPayConfig.getApiV3Key(), 2);
                String orderNo = resourceMap.get("out_trade_no").toString();
                String outRefundNo = resourceMap.get("out_refund_no").toString();

                R<TicOrder> ticOrderR = remoteOrderService.orderPayDetail(orderNo);
                if(ticOrderR.getCode()!= HttpStatus.SUCCESS){
                    logger.error("订单不存在");
                }else {
                    TicOrder data = ticOrderR.getData();
                    logger.info("订货信息，"+data.toString());
                    String orderStatus = data.getOrderStatus();
                    if(orderStatus.equals("7")){
                        //退款回调修改订单
                        AjaxResult ajaxResult = remoteOrderService.orderBack(data.getOrderId());

                        // AjaxResult ajaxResult = remoteTicketService.paySucessStatus(data.getOrderId());
                         logger.info("退款回调修改订单，"+ajaxResult.toString());

                        try {
                            TicPayRefundLog ticPayRefundLog = ticPayRefundLogService.selectTicPayRefundLogByOutRefundNo(outRefundNo);
                            if(ticPayRefundLog!=null){
                                ticPayRefundLog.setPayRefundJson(JSONObject.toJSONString(resourceMap));
                                ticPayRefundLog.setUpdateBy(SecurityUtils.getUsername());
                                ticPayRefundLog.setUpdateTime(DateUtils.getNowDate());
                                ticPayRefundLogService.updateTicPayRefundLog(ticPayRefundLog);
                            }
                        } catch (Exception e) {
                            logger.error(String.format("退款回调修改记录异常%s", e.getMessage()));
                        }


                    }

                }



//                String transactionId = resourceMap.get("transaction_id").toString();
                logger.info("退款所有参数" + resourceMap);

                // TODO 根据订单号，做幂等处理，并且在对业务数据进行状态检查和处理之前，要采用数据锁进行并发控制，以避免函数重入造成的数据混乱
                // 更改订单状态为已退款
                logger.warn("=========== 根据订单号，做幂等处理 ===========");
            } finally {
                //要主动释放锁
                lock.unlock();
            }
        }

        //成功应答
        return trueMsg(response);
    }

    private Map<String, Object> getNotifyBody(HttpServletRequest request) {
        //处理通知参数
        String body = WechatPayValidator.readData(request);
        logger.info("回调参数：{}", body);

        // 转换为Map
        Map<String, Object> bodyMap = JSONObject.parseObject(body, new TypeReference<Map<String, Object>>() {
        });
        // 微信的通知ID（通知的唯一ID）
        String notifyId = bodyMap.get("id").toString();
        // 验证签名信息
        WechatPayValidator wechatPayValidator
                = new WechatPayValidator(verifier, notifyId, body);
        if (!wechatPayValidator.validate(request)) {

            logger.error("通知验签失败");
            return null;
        }
        logger.info("通知验签成功");
        return bodyMap;
    }

    private Map<String, String> falseMsg(HttpServletResponse response) {
        Map<String, String> resMap = new HashMap<>(8);
        //失败应答
        response.setStatus(500);
        resMap.put("code", "ERROR");
        resMap.put("message", "通知验签失败");
        return resMap;
    }

    private Map<String, String> trueMsg(HttpServletResponse response) {
        Map<String, String> resMap = new HashMap<>(8);
        //成功应答
        response.setStatus(200);
        resMap.put("code", "SUCCESS");
        resMap.put("message", "成功");
        return resMap;
    }
}